mod abstract_unit;
mod creatures;

use abstract_unit::logic::Logic;
use ggez::{Context, GameError, graphics, glam::Vec2};
use rand::Rng;
use rand_distr::{Distribution, Normal};



pub struct State{
    units: Vec<Box<dyn abstract_unit::unit::Unit>>
}

impl State{
    pub fn new(_ctx: &mut Context) -> State {
        let mut units: Vec<Box<dyn abstract_unit::unit::Unit>> = vec![];
        let mut rng = rand::thread_rng();
        for _i in 0..20 {
            let location = Vec2 {x: rng.gen_range(0.0..800.0), y: rng.gen_range(0.0..600.0)};
            let normal = Normal::new(0.5, 0.2).unwrap();
            let intelligence = normal.sample(&mut rng) as f32;
            let luck = normal.sample(&mut rng) as f32;
            let willpower = normal.sample(&mut rng) as f32;
            let coins = normal.sample(&mut rng) as f32;
            let logic = Logic{intelligence, luck, willpower, coins};
            let unit = creatures::predator::Predator::new(logic, location);
            units.push(Box::new(unit));
        }
        State { units }
    }
}

impl ggez::event::EventHandler<GameError> for State {
    fn update(&mut self, ctx: &mut Context) -> Result<(), GameError> {
        for i in 0..self.units.len() {
            for j in 0..self.units.len() {
                if i != j {
                    let force = -self.units[j].attract(&self.units[i]);
                    let coeff = self.units[i].get_willpower()*10.0;
                    self.units[i].apply_force(force/coeff);
                }
            }

            let dirvector = Vec2{x: ctx.mouse.position().x, y: ctx.mouse.position().y} - self.units[i].get_location();
            let mut distance = dirvector.length();
            distance = distance.clamp(5.0, 25.0);
            let g = 10.0;
            let force = dirvector.normalize()*g*self.units[i].get_mass()/(distance*distance);
            let coeff = self.units[i].get_intelligence()*10.0;
            self.units[i].apply_force(force/coeff);

            let force = -self.units[i].get_velocity().normalize();
            let coeff = self.units[i].get_luck()*10.0;
            self.units[i].apply_force(force/coeff);

            self.units[i].update(ctx);
        }
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> Result<(), GameError> {
        let mut canvas = graphics::Canvas::from_frame(ctx, graphics::Color::WHITE);
        for mover in &mut self.units {
            mover.display(ctx, &mut canvas);
        }
        canvas.finish(ctx)?;
        Ok(())
    }
}